﻿using System.Data;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

namespace TPXSDK.NET.Share;

/// <summary>
/// 数据单位转换/数据处理/类型判读等工具类
/// </summary>
public class DataUtils
{
    /// <summary>
    /// 弧度转度
    /// </summary>
    public static double Rad2Deg(double rad) { return rad * 180.0 / Math.PI; }
    /// <summary>
    /// 度转弧度
    /// </summary>
    public static double Deg2Rad(double deg) { return deg * Math.PI / 180.0; }
    /// <summary>
    /// 弧度转度
    /// </summary>
    public static float Rad2Deg(float rad) { return rad * 180.0f / 3.1415926f; }
    /// <summary>
    /// 度转弧度
    /// </summary>
    public static float Deg2Rad(float deg) { return deg * 3.1415926f / 180.0f; }

    /// <summary>
    /// 英寸转米
    /// </summary>
    public static double Feet2Meter(double val) { return 0.3048 * val; }
    /// <summary>
    /// 米转英寸
    /// </summary>
    public static double Meter2Feet(double val) { return val / 0.3048; }
    /// <summary>
    /// 英寸转米
    /// </summary>
    public static float Feet2Meter(float val) { return 0.3048f * val; }
    /// <summary>
    /// 米转英寸
    /// </summary>
    public static float Meter2Feet(float val) { return val / 0.3048f; }

    /// <summary>
    /// 从km/h到ft/s;
    /// </summary>
    public static double Kmph2Ftps(double val) { return val / 0.3048 / 3.6; }
    /// <summary>
    /// 从ft/s到km/h;
    /// </summary>
    public static double Ftps2Kmph(double val) { return 3.6 * 0.3048 * val; }
    /// <summary>
    /// 从kts(节)到ft/s;
    /// </summary>
    public static double Kts2Ftps(double val) { return 1852.0 / 3600.0 / 0.3048 * val; }
    /// <summary>
    /// 从ft/s到kts(节);
    /// </summary>
    public static double Ftps2Kts(double val) { return 3600.0 * 0.3048 / 1852 * val; }
    /// <summary>
    /// 从kts(节)到km/h;
    /// </summary>
    public static double Kts2Kmph(double val) { return 1.852 * val; }
    /// <summary>
    /// 从km/h到kts(节);
    /// </summary>
    public static double Kmph2Kts(double val) { return val / 1.852; }
    /// <summary>
    /// 从km/h到m/s
    /// </summary>
    public static double Kmph2Mps(double val) { return val / 3.6; }
    /// <summary>
    /// 从m/s到km/h
    /// </summary>
    public static double Mps2Kmph(double val) { return val * 3.6; }
    /// <summary>
    /// 从m/s到ft/s
    /// </summary>
    public static double Mps2Fts(double val) { return Meter2Feet(val); }

    /// <summary>
    /// 将Hex数据转换成字符串，例如 0xae00cf => "AE00CF"
    /// </summary>
    public static string HexStr(byte[] bytes)
    {
        if (bytes == null || bytes.Length == 0)
            return string.Empty;
        var strB = new StringBuilder();
        foreach (var t in bytes)
            strB.Append(t.ToString("X2"));
        return strB.ToString();
    }

    /// <summary>
    /// 将Hex数据转换成字符串，例如 0xae00cf => "AE00CF"
    /// </summary>
    public static string HexStr(byte[] bytes, int len, char delimiter = ' ')
    {
        if (bytes == null) return string.Empty;

        var strB = new StringBuilder();
        len = len < bytes.Length ? len : bytes.Length;
        for (var i = 0; i < len; i++)
        {
            strB.Append($"{bytes[i]:X2}{delimiter}");
        }
        return strB.ToString();
    }
    /// <summary>
    /// 字节流转换成16进制字符串
    /// </summary>
    public static string HexStr(byte[] bytes, int offset, int len, char delimiter = ' ')
    {
        if (bytes == null || bytes.Length == 0)
            return string.Empty;

        var strB = new StringBuilder();
        len = len < bytes.Length - offset ? len : bytes.Length - offset;
        for (var i = 0; i < len; i++)
        {
            strB.Append($"{bytes[i + offset]:X2}{delimiter}");
        }
        return strB.ToString();
    }

    /// <summary>
    /// 将16进制的字符串数据转换成字节数组，例如：
    /// "3031" 转成new byte[]{ 0x30, 0x31}:
    /// </summary>
    public static byte[] HexStrToByte(string hexStr)
    {
        if (string.IsNullOrEmpty(hexStr))
        {
            return [];
        }
        var returnBytes = new byte[hexStr.Length / 2];
        for (var i = 0; i < returnBytes.Length; i++)
        {
            returnBytes[i] = Convert.ToByte(hexStr.Substring(i * 2, 2), 16);
        }
        return returnBytes;
    }

    /// <summary>判断字符串是否为数字</summary>
    /// <param name="strInput">输入字符串</param>
    /// <returns>true/false</returns>
    public static bool IsNumeric(string strInput)
    {
        if (string.IsNullOrEmpty(strInput))
            return false;
        //@"^[+-]?\d*[.]?\d*$"
        var reg = new Regex(@"^[-]?\d+[.]?\d*$");
        return reg.IsMatch(strInput);
    }

    /// <summary>
    /// 判断是否为有效IP地址
    /// </summary>
    public static bool IsIpAddr(string strInput)
    {
        if (string.IsNullOrEmpty(strInput))
            return false;

        var reg = new Regex(@"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b");
        return reg.IsMatch(strInput);
    }

    /// <summary>
    /// 是不是时间类型数据
    /// </summary>
    public static bool IsDateTime(string strDate)
    {
        var reg =
            new Regex(
                @"(((^((1[8-9]\d{2})|([2-9]\d{3}))([-\/\._])(10|12|0?[13578])([-\/\._])(3[01]|[12][0-9]|0?[1-9]))|(^((1[8-9]\d{2})|([2-9]\d{3}))([-\/\._])(11|0?[469])([-\/\._])(30|[12][0-9]|0?[1-9]))|(^((1[8-9]\d{2})|([2-9]\d{3}))([-\/\._])(0?2)([-\/\._])(2[0-8]|1[0-9]|0?[1-9]))|(^([2468][048]00)([-\/\._])(0?2)([-\/\._])(29))|(^([3579][26]00)([-\/\._])(0?2)([-\/\._])(29))|(^([1][89][0][48])([-\/\._])(0?2)([-\/\._])(29))|(^([2-9][0-9][0][48])([-\/\._])(0?2)([-\/\._])(29))|(^([1][89][2468][048])([-\/\._])(0?2)([-\/\._])(29))|(^([2-9][0-9][2468][048])([-\/\._])(0?2)([-\/\._])(29))|(^([1][89][13579][26])([-\/\._])(0?2)([-\/\._])(29))|(^([2-9][0-9][13579][26])([-\/\._])(0?2)([-\/\._])(29)))((\s+(0?[1-9]|1[012])(:[0-5]\d){0,2}(\s[AP]M))?$|(\s+([01]\d|2[0-3])(:[0-5]\d){0,2})?$))");
        return reg.IsMatch(strDate);
    }

    /// <summary>
    /// 浮点数判断是否为零(单精度)
    /// </summary>
    public static bool IsZero(float val)
    {
        return Math.Abs(val) < float.Epsilon;
    }

    /// <summary>
    /// 浮点数判断是否为零(双精度)
    /// </summary>
    public static bool IsZero(double val)
    {
        return Math.Abs(val) < double.Epsilon;
    }

    /// <summary>
    /// 浮点数判断是否相等(双精度)
    /// </summary>
    public static bool IsEqual(double val1, double val2)
    {
        return Math.Abs(val1 - val2) < double.Epsilon;
    }

    /// <summary>
    /// 浮点数判断是否相等(单精度)
    /// </summary>
    public static bool IsEqual(float val1, float val2)
    {
        return Math.Abs(val1 - val2) < float.Epsilon;
    }

    /// <summary>
    /// 检查邮件地址是否合法
    /// </summary>
    public static bool IsEmail(string email)
    {
        email = email.Trim();
        const string regexString =
            @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
        var regex = new Regex(regexString);
        return regex.IsMatch(email);
    }

    /// <summary>
    /// Checks if a string is base64 encoded
    /// </summary>
    /// <param name="str" />The base64 encoded string
    /// <returns>Base64 encoded stringt</returns>
    public static bool IsBase64String(string str)
    {
        str = str.Trim();
        return str.Length % 4 == 0 &&
               Regex.IsMatch(str, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None);

    }

    /// <summary>
    /// 将struct类型转换为byte[]
    /// </summary>
    public static byte[] StructToBytes(object structObj)
    {
        var size = Marshal.SizeOf(structObj);
        return StructToBytes(structObj, size);
    }

    /// <summary>
    /// 将struct类型转换为byte[]
    /// </summary>
    public static byte[] StructToBytes(object structObj, int size)
    {
        var buffer = Marshal.AllocHGlobal(size);
        try//struct_bytes转换
        {
            Marshal.StructureToPtr(structObj, buffer, false);
            var bytes = new byte[size];
            Marshal.Copy(buffer, bytes, 0, size);
            return bytes;
        }
        catch (Exception ex)
        {
            throw new Exception("Error in StructToBytes ! " + ex.Message);
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }

    /// <summary>
    /// 将byte[]还原为指定的struct,该函数的泛型仅用于自定义结构
    /// startIndex：数组中 Copy 开始位置的从零开始的索引。
    /// length：要复制的数组元素的数目。
    /// </summary>
    public static T? BytesToStruct<T>(byte[] bytes, int startIndex, int length)
    {
        if (bytes == null) return default;
        if (bytes.Length <= 0) return default;
        var buffer = Marshal.AllocHGlobal(length);
        try//struct_bytes转换
        {
            Marshal.Copy(bytes, startIndex, buffer, length);
            return (T?)Marshal.PtrToStructure(buffer, typeof(T));
        }
        catch (Exception ex)
        {
            throw new Exception("Error in BytesToStruct!" + ex.Message);
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }
    /// <summary>
    /// 将字节流序列化成泛型数据结构
    /// </summary>
    public static T? BytesToStruct<T>(byte[] bytes)
    {
        if (bytes == null) return default;
        if (bytes.Length <= 0) return default;
        var buffer = Marshal.AllocHGlobal(bytes.Length);
        try//struct_bytes转换
        {
            Marshal.Copy(bytes, 0, buffer, bytes.Length);
            return (T?)Marshal.PtrToStructure(buffer, typeof(T));
        }
        catch (Exception ex)
        {
            throw new Exception("Error in BytesToStruct ! " + ex.Message);
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }
    /// <summary>
    /// 将字节流序列化成泛型数据结构
    /// </summary>
    public static T? BytesToStruct<T>(byte[] bytes, int offset)
    {
        if (bytes == null) return default;
        var len = bytes.Length - offset;
        if (len <= 0) return default;
        var buffer = Marshal.AllocHGlobal(len);
        try//struct_bytes转换
        {
            Marshal.Copy(bytes, offset, buffer, len);
            return (T?)Marshal.PtrToStructure(buffer, typeof(T));
        }
        catch (Exception ex)
        {
            throw new Exception("Error in BytesToStruct ! " + ex.Message);
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }

    /// <summary>
    /// 将数据结构struct映射成数据表格
    /// </summary>
    public static DataTable Reflect2DataTable<T>(string tabName) where T : struct
    {
        var dt = new DataTable(tabName);
        var t = typeof(T);
        foreach (var p in t.GetMembers())
        {
            if (p.MemberType != MemberTypes.Field || "CRC" == p.Name) continue;
            dt.Columns.Add(p.Name);
        }
        return dt;
    }

    /// <summary>
    /// 按照如下顺序获得uint类型的字节数组
    /// [B0-L] [B1] [B2] [B3-H]
    /// </summary>
    public static byte[] GetBytes(uint val)
    {
        var res = new byte[4];
        res[0] = (byte)(val & 0xFF);
        res[1] = (byte)(val >> 8 & 0xFF);
        res[2] = (byte)(val >> 16 & 0xFF);
        res[3] = (byte)(val >> 24 & 0xFF);

        return res;
    }

    /// <summary>
    /// wrap an angle in degrees to 0~360
    /// </summary>
    public static float Wrap360(float bearing)
    {
        /* value is inf or NaN */
        if (float.IsInfinity(bearing))
        {
            return bearing;
        }

        var c = 0;
        while (bearing >= 360.0f)
        {
            bearing -= 360.0f;

            if (c++ > 3)
            {
                return float.NaN;
            }
        }

        c = 0;
        while (bearing < 0.0f)
        {
            bearing += 360.0f;

            if (c++ > 3)
            {
                return float.NaN;
            }
        }

        return bearing;
    }

    public static double Wrap360(double bearing)
    {
        /* value is inf or NaN */
        if (double.IsInfinity(bearing))
        {
            return bearing;
        }

        var c = 0;
        while (bearing >= 360.0f)
        {
            bearing -= 360.0f;

            if (c++ > 3)
            {
                return double.NaN;
            }
        }

        c = 0;
        while (bearing < 0.0f)
        {
            bearing += 360.0f;

            if (c++ > 3)
            {
                return double.NaN;
            }
        }

        return bearing;
    }

    /// <summary>
    /// wrap an angle in degrees to -180..180
    /// </summary>
    public static float Wrap180(float bearing)
    {
        /* value is inf or NaN */
        if (float.IsInfinity(bearing))
        {
            return bearing;
        }

        var c = 0;
        while (bearing >= 180.0f)
        {
            bearing -= 360.0f;
            if (c++ > 3)
            {
                return float.NaN;
            }
        }

        c = 0;
        while (bearing < -180.0f)
        {
            bearing += 360.0f;

            if (c++ > 3)
            {
                return float.NaN;
            }
        }

        return bearing;
    }

    public static double Wrap180(double bearing)
    {
        /* value is inf or NaN */
        if (double.IsInfinity(bearing))
        {
            return bearing;
        }

        var c = 0;
        while (bearing >= 180.0f)
        {
            bearing -= 360.0f;
            if (c++ > 3)
            {
                return double.NaN;
            }
        }

        c = 0;
        while (bearing < -180.0f)
        {
            bearing += 360.0f;

            if (c++ > 3)
            {
                return double.NaN;
            }
        }

        return bearing;
    }

    /// <summary>
    /// wrap an angle in radians to -PI ~ PI (equivalent to +- 180 deg)
    /// </summary>
    public static double WrapPI(double radian)
    {
        var res = Wrap2PI(radian);
        if (res > Math.PI) res -= Math.PI * 2;
        return res;
    }

    /// <summary>
    /// wrap an angle in radians to 0 ~ 2PI
    /// </summary>
    public static double Wrap2PI(double radian)
    {
        var res = radian % (Math.PI * 2);
        if (res < 0) res += Math.PI * 2;
        return (float)res;
    }

    public static double Constrain(double val, double min_val, double max_val)
    {
        return val < min_val ? min_val : val > max_val ? max_val : val;
    }

    // 得到一个字的高位和低位字节
    public static byte WORD_LO(ushort a) { return (byte)(a & 0xFF); }
    public static byte WORD_HI(ushort a) { return (byte)(a >> 8); }

    public static byte DWORD_B1(uint a) { return (byte)(a & 0xFF); }
    public static byte DWORD_B2(uint a) { return (byte)(a >> 8 & 0xFF); }
    public static byte DWORD_B3(uint a) { return (byte)(a >> 16 & 0xFF); }
    public static byte DWORD_B4(uint a) { return (byte)(a >> 24 & 0xFF); }

    public static byte DWORD_B1(int a) { return (byte)(a & 0xFF); }
    public static byte DWORD_B2(int a) { return (byte)(a >> 8 & 0xFF); }
    public static byte DWORD_B3(int a) { return (byte)(a >> 16 & 0xFF); }
    public static byte DWORD_B4(int a) { return (byte)(a >> 24 & 0xFF); }

    public static byte BIT8_SET(byte x, int n) { return (byte)(x | 1 << n); }
    public static bool BIT8_TST(byte x, int n) { return (x & 1 << n) != 0; }
    public static byte BIT8_CLR(byte x, int n) { return (byte)(x & ~(1 << n)); }

    public static ushort BIT16_SET(ushort x, int n) { return (ushort)(x | 1 << n); }
    public static bool BIT16_TST(ushort x, int n) { return (x & 1 << n) != 0; }
    public static ushort BIT16_CLR(ushort x, int n) { return (ushort)(x & ~(1 << n)); }

    public static uint BIT32_SET(uint x, int n) { return x | (uint)(1 << n); }
    public static bool BIT32_TST(uint x, int n) { return (x & 1 << n) != 0; }
    public static uint BIT32_CLR(uint x, int n) { return (uint)(x & ~(1 << n)); }

    // 将两个字节合成一个字
    public static ushort GEN_WORD(byte lo, byte hi) { return (ushort)(lo + (hi << 8)); }
    public static short GEN_WORD_S(byte lo, byte hi) { return (short)(lo + (hi << 8)); }
    public static int GEN_INT32(byte b1, byte b2) { return b1 | b2 << 8; }
    public static int GEN_INT32(byte b1, byte b2, byte b3) { return b1 | b2 << 8 | b3 << 16; }
    public static int GEN_INT32(byte b1, byte b2, byte b3, byte b4) { return b1 | b2 << 8 | b3 << 16 | b4 << 24; }
    public static uint GEN_UINT32(byte b1, byte b2, byte b3, byte b4) { return (uint)(b1 | b2 << 8 | b3 << 16 | b4 << 24); }
    public static uint GEN_UINT32(byte[] b, int offset = 0)
    {
        return (uint)(b[offset] | b[offset + 1] << 8 | b[offset + 2] << 16 | b[offset + 3] << 24);
    }

    public static int GEN_INT32(byte[] b, int offset = 0)
    {
        return b[offset] | b[offset + 1] << 8 | b[offset + 2] << 16 | b[offset + 3] << 24;
    }


    /// <summary>
    /// 将十进制度格式转换为度分秒格式
    /// </summary>
    public static (int Degrees, int Minutes, double Seconds) DDtoDMS(double dd)
    {
        int degrees = (int)dd;
        double decimalPart = Math.Abs(dd - degrees);
        int minutes = (int)(decimalPart * 60);
        double seconds = (decimalPart * 60 - minutes) * 60;
        return (degrees, minutes, seconds);
    }

    /// <summary>
    /// 将十进制度格式转换为度分格式
    /// </summary>
    public static (int Degrees, double Minutes) DDtoDM(double dd)
    {
        int degrees = (int)dd;
        double decimalPart = Math.Abs(dd - degrees);
        double minutes = decimalPart * 60;
        return (degrees, minutes);
    }

    /// <summary>
    /// 将度分秒格式转换为十进制度格式
    /// </summary>
    public static double DMSToDD(int degrees, int minutes, double seconds)
    {
        double dd = degrees + (minutes / 60.0) + (seconds / 3600.0);
        return dd;
    }

    /// <summary>
    /// 将度分格式转换为十进制度格式
    /// </summary>
    public static double DMToDD(int degrees, double minutes)
    {
        double dd = degrees + (minutes / 60.0);
        return dd;
    }

}
